/**
 * 
 */
package org.estela.ml.dataset;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Arrays;

/**
 * @version $Revision$
 * @date Apr 22, 2006
 * @author <a href="mailto:akantek@nyse.com">Antonio Kantek</a>
 */
public class DiscreteAttribute extends AbstractAttribute {
	private static final long serialVersionUID = 1L;
	
	/** */
	private String[] categories;	

	/**
	 * 
	 */
	public DiscreteAttribute() {
		super();
	}
	
	/**
	 * 
	 * @param index
	 * @param name
	 */
	public DiscreteAttribute(int index, String name, String[] categories) {
		super(index, name);
		this.categories = categories;
	}

	/**
	 * @param index
	 * @param name
	 * @param weight
	 */
	public DiscreteAttribute(int index, String name, double weight, String[] categories) {
		super(index, name, weight);
		this.categories = categories;
	}
	
	/*
	 *  (non-Javadoc)
	 * @see dataset.Attribute#isDiscrete()
	 */
	public boolean isDiscrete() {
		return true;
	}	

	/* (non-Javadoc)
	 * @see dataset.Attribute#encode(java.lang.Object)
	 */
	public double encode(Object value) {
		if (value == null) {
			return Double.NaN;
		}
		for(int i=0;i<this.categories.length;i++) {
			if (this.categories[i].equals(value)) {
				return i;
			}
		}
		throw new IllegalArgumentException("Invalid value: " + value + " values allowed: " + this);
	}

	/* (non-Javadoc)
	 * @see dataset.Attribute#decode(double)
	 */
	public Object decode(double d) {
		if (d == Double.NaN) {
			return null;
		}
		if (d >= this.categories.length) {
			throw new IllegalArgumentException("Invalid index: " + d);
		}
		return this.categories[(int) d];		
	}

	/*
	 *  (non-Javadoc)
	 * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
	 */
	public void writeExternal(ObjectOutput out) throws IOException {
		super.writeExternal(out);
		out.writeInt(this.categories.length);
		for (int i = 0; i < this.categories.length; i++) {
			out.writeUTF(this.categories[i]);
		}

	}

	/* (non-Javadoc)
	 * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
	 */
	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException {
		super.readExternal(in);
		this.categories = new String[in.readInt()];
		for (int i = 0; i < this.categories.length; i++) {
			this.categories[i] = in.readUTF();
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	/**
	 * @return Returns the categories.
	 */
	public String[] getCategories() {
		return categories;
	}
	
	@Override
	public String toString() {
		StringBuilder buff = new StringBuilder();
		buff.append("[DiscreteAttribute name=").append(this.name);
		buff.append(", weight=").append(this.weight);
		buff.append(", index=").append(this.index);
		buff.append(", categories=").append(Arrays.toString(this.categories));
		buff.append(']');
		return buff.toString();
	}
	
	@Override
	public int hashCode() {
		int hash = super.hashCode();
		hash *= Arrays.hashCode(this.categories);
        return hash;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof DiscreteAttribute) {
			DiscreteAttribute other = (DiscreteAttribute) obj;
			return 
				this.name.equals(other.name) &&
				Arrays.equals(this.categories, other.categories);
		}
		return false;
	}
}
